#include "SerialPortIO.h"

#define TAG "SerialPort"
#include "elog.h"
#define NANO_LIGD(tag,...)  elog_d(tag,__VA_ARGS__)
#define NANO_LOGI(tag,...)  elog_i(tag,__VA_ARGS__)
#define NANO_LOGW(tag,...)  elog_i(tag,__VA_ARGS__)
#define NANO_LOGE(tag,...)  elog_i(tag,__VA_ARGS__)
#define NANO_HEXDUMP(tag,buf,len)   elog_hexdump(tag,16,buf,len)

SerialPortIO::SerialPortIO(SerialPortInfo* info,
             uint32_t boundRate,
             uint8_t dataBit,
             SerialPortStopBit stopBit,
             SerialPortVerify verify)
    : NanoIO( "SerialPort" )
{
    this->_portInfo = *info;
    this->_bound = boundRate;
    this->_dataBit = dataBit;
    this->_stopBit = stopBit;
    this->_verifyMode = verify;
    this->_port = NULL;
}

SerialPortIO::~SerialPortIO()
{
    if( isOpen() )
    {
        close();
    }
}

bool SerialPortIO::open()
{
    QList<QSerialPortInfo> qlist = QSerialPortInfo::availablePorts();
    for( auto it = qlist.begin() ; it != qlist.end() ; it++ )
    {
        if( !strcmp( (const char*)it->portName().toLatin1().data() , _portInfo.portName ) )
        {
            _port = new QSerialPort(*it);
            _port->setBaudRate( _bound );
            _port->setDataBits( (QSerialPort::DataBits)_dataBit );

            //映射QSerialPort，隔离，为以后增加其他串口库的加入为应用层提供统一接口
            QSerialPort::Parity parity;
            switch( _verifyMode ){
            case NoParity:
                    parity = QSerialPort::NoParity;
                break;
            case EvenParity:
                    parity = QSerialPort::EvenParity;
                break;
            case OddParity:
                    parity = QSerialPort::OddParity;
                break;
            case SpaceParity:
                    parity = QSerialPort::SpaceParity;
                break;
            case MarkParity:
                    parity = QSerialPort::MarkParity;
                break;
            default:
                    parity = QSerialPort::UnknownParity;
                break;
            }
            _port->setParity( parity );

            QSerialPort::StopBits stopBit;
            switch ( _stopBit ) {
            case OneStop:
                stopBit = QSerialPort::OneStop;
                break;
            case OneAndHalfStop:
                stopBit = QSerialPort::OneAndHalfStop;
                break;
            case TowStop:
                stopBit = QSerialPort::TwoStop;
                break;
            default:
                stopBit = QSerialPort::UnknownStopBits;
                break;
            }
            _port->setStopBits( stopBit );

            NANO_LOGI(TAG,"name:%s bound:%d",this->_portInfo.portName,this->_bound);
            NANO_LOGI(TAG,"name:%s stop bit enum:%d",this->_portInfo.portName,this->_stopBit);
            NANO_LOGI(TAG,"name:%s verify mode enum:%d",this->_portInfo.portName,this->_verifyMode);

            if( _port->open(QIODevice::ReadWrite) )
            {
                NANO_LOGI(TAG,"Open SerialPort:%s pass." , this->_portInfo.portName);
                return true;
            }

            delete _port;
            NANO_LOGI(TAG,"QSerialPort open SerialPort(%s) failed." , this->_portInfo.portName);
            _port = NULL;
            return false;
        }
    }

    NANO_LOGW(TAG,"Can`t find SerialPort(%s),open failed." , this->_portInfo.portName);
    return false;
}

bool SerialPortIO::close()
{
    return true;
}

bool SerialPortIO::isOpen()
{
    return _port ? true : false;
}

int SerialPortIO::read(uint8_t* data , uint16_t len , uint32_t timeout_ms)
{
    if( !isOpen() )
        return 0;

    (void)timeout_ms;

    return this->_port->read((char*)data,len);
}

int SerialPortIO::write(uint8_t* data , uint16_t len , uint32_t timeout_ms)
{
    if( !isOpen() )
    {
        return -1;
    }

    (void)timeout_ms;

    return _port->write( (const char*)data , len );
}

bool SerialPortIO::setBound(uint32_t bound)
{
    if( isOpen() )
        return false;

    _bound = bound;
    return true;
}

bool SerialPortIO::setDataBit(uint8_t dataBit)
{
    if( isOpen() )
        return false;

    _dataBit = dataBit;
    return true;
}

bool SerialPortIO::setStopBit(SerialPortStopBit stopBit)
{
    if( isOpen() )
        return false;

    _stopBit = stopBit;
    return true;
}

bool SerialPortIO::setVerifyMode(SerialPortVerify verifyMode)
{
    if( isOpen() )
        return false;

    _verifyMode = verifyMode;
    return true;
}

std::list<SerialPortIO::SerialPortInfo> SerialPortIO::getSerialPortInfoList()
{
    NANO_LOGI(TAG,"Scan serialport...");

    QList<QSerialPortInfo> qlist = QSerialPortInfo::availablePorts();
    std::list<SerialPortInfo> portList;

    NANO_LOGI(TAG,"Find %d serialport.",qlist.length());

    for( auto it = qlist.begin() ; it != qlist.end() ; it++ )
    {
        SerialPortInfo portInfo;
        sscanf( (const char*)it->description().toLatin1().data() , "%63s" , portInfo.description );
        sscanf( (const char*)it->portName().toLatin1().data() , "%31s" , portInfo.portName );
        portList.push_back(portInfo);
        NANO_LOGI(TAG,"%s - %s." , portInfo.portName , portInfo.description );
    }

    return portList;
}
